/**
 * @file litefoc_port.c
 * @author wangshixin (gin0101@126.com)
 * @brief LiteFOC 硬件引脚配置、PWM控制及角度获取
 * @version 1.0.0
 * @date 2023-05-28
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#include "litefoc_port.h"

#include "gd32f1x0.h"
#include "tle5012b.h"

/********************************************** 内部函数定义 BEGIN **********************************************/
/**
 * @brief 电源控制配置
 * 
 */
static void _litefoc_port_init_power(void)
{
    rcu_periph_clock_enable(RCU_GPIOB);

    // 电机电源控制引脚配置;
	gpio_mode_set(MOTOR_POWER_ENABLE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, MOTOR_POWER_ENABLE_PIN);
	gpio_output_options_set(MOTOR_POWER_ENABLE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, MOTOR_POWER_ENABLE_PIN);
}


/**
 * @brief pwm 硬件功能配置
 * 
 */
static void _litefoc_port_init_pwm(void)
{
    /* -----------------------------------------------------------------------
    使用 TIMER0 产生 3 路 PWM 信号:
    TIMER0 时钟：TIMER0CLK = SystemCoreClock / (prescaler + 1)
	PWM 频率 = TIMER0CLK / (period + 1)
    PWM 占空比 = ((channel value)/ (period + 1)) * 100
    ----------------------------------------------------------------------- */

    timer_oc_parameter_struct timer_ocintpara = {0};
    timer_parameter_struct timer_initpara = {0};

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);

    // 电机 U V W 使能控制引脚配置;
	gpio_mode_set(MOTOR_U_ENABLE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, MOTOR_U_ENABLE_PIN);
	gpio_output_options_set(MOTOR_U_ENABLE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, MOTOR_U_ENABLE_PIN);
	gpio_mode_set(MOTOR_V_ENABLE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, MOTOR_V_ENABLE_PIN);
	gpio_output_options_set(MOTOR_V_ENABLE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, MOTOR_V_ENABLE_PIN);
	gpio_mode_set(MOTOR_W_ENABLE_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, MOTOR_W_ENABLE_PIN);
	gpio_output_options_set(MOTOR_W_ENABLE_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, MOTOR_W_ENABLE_PIN);
	
	// 电机 U V W PWM 输出控制引脚配置;
	gpio_mode_set(MOTOR_U_IN_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, MOTOR_U_IN_PIN | MOTOR_V_IN_PIN | MOTOR_W_IN_PIN);
	gpio_af_set(MOTOR_U_IN_PORT, GPIO_AF_2, MOTOR_U_IN_PIN | MOTOR_V_IN_PIN | MOTOR_W_IN_PIN);
	gpio_output_options_set(MOTOR_U_IN_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, MOTOR_U_IN_PIN | MOTOR_V_IN_PIN | MOTOR_W_IN_PIN);
    
    rcu_periph_clock_enable(RCU_TIMER0);
    timer_deinit(TIMER0);

    /* TIMER0 configuration */
    timer_initpara.prescaler         = 15;	// 最小14；
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 255;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER0,&timer_initpara);
    
    /* CH0, CH1 and CH2 configuration in PWM mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;

    timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
    timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);
    timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocintpara);

    /* CH0 configuration in PWM mode1 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 0);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);

    /* CH1 configuration in PWM mode1 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, 0);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);

    /* CH2 configuration in PWM mode1 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, 0);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_DISABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER0);
    
    /* enable TIMER0 primary output */
    timer_primary_output_config(TIMER0, ENABLE);
    
    /* auto-reload preload enable */
    timer_enable(TIMER0);
}


/**
 * @brief 电机绝对角度传感器配置
 * 
 */
static void _litefoc_port_init_sensor(void)
{
	spi_parameter_struct  spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);

	/* configure SPI0 GPIO: CS, SCK, MOSI, MISO */
    gpio_mode_set(SPI_CSQ_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, SPI_CSQ_PIN);
    gpio_output_options_set(SPI_CSQ_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI_CSQ_PIN);
	gpio_af_set(SPI_SCK_PORT, GPIO_AF_0, SPI_SCK_PIN | SPI_MISO_PIN |SPI_MOSI_PIN);
    gpio_mode_set(SPI_SCK_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI_SCK_PIN | SPI_MISO_PIN |SPI_MOSI_PIN);
    gpio_output_options_set(SPI_SCK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI_SCK_PIN | SPI_MISO_PIN |SPI_MOSI_PIN);

	rcu_periph_clock_enable(RCU_SPI0);
	spi_i2s_deinit(SPI0);
	spi_struct_para_init(&spi_init_struct);
	/* configure SPI0 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_16BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_8;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);

	/* enable SPI */
    spi_enable(SPI0);
}
/********************************************** 内部函数定义 END ************************************************/


/**
 * @brief LiteFOC 硬件接口初始化
 * 
 */
void litefoc_port_init(void)
{
    _litefoc_port_init_power();
    _litefoc_port_init_pwm();
    _litefoc_port_init_sensor();
}


/**
 * @brief pwm 值设置
 * 
 * @param   ucU 电机U相PWM值
 * @param   ucV 电机V相PWM值
 * @param   ucW 电机W相PWM值
 * 
 * @return  0 - 设置成功， 其他 - 设置失败
 */
unsigned char litefoc_port_set_pwm(unsigned char ucU, unsigned char ucV, unsigned char ucW)
{
    unsigned char res = 0;

    TIMER_CH0CV(TIMER0) = ucU;
    TIMER_CH1CV(TIMER0) = ucV;
    TIMER_CH2CV(TIMER0) = ucW;

    return res;
}


/**
 * @brief 电机绝对角度获取
 * 
 * @param   fAngle 角度指针
 * 
 * @return  0 - 获取成功， 其他 - 获取失败
 */
unsigned char litefoc_port_get_angle(float *fAngle)
{
    unsigned char res = 0;

    *fAngle = ReadAngle();
    if (*fAngle > 360.0f || *fAngle < 0.0f) res = 1;

    return res;
}


/**
 * @brief 电机电源控制
 * 
 */
void litefoc_port_power(unsigned char ucEnable)
{
	bit_status bit = ucEnable > 0 ? SET : RESET;
	
    // 启动电机电源;
	gpio_bit_write(MOTOR_POWER_ENABLE_PORT, MOTOR_POWER_ENABLE_PIN, bit);
	
	// 使能电机 U V W 输出;
	gpio_bit_write(MOTOR_U_ENABLE_PORT, MOTOR_U_ENABLE_PIN, bit);
	gpio_bit_write(MOTOR_V_ENABLE_PORT, MOTOR_V_ENABLE_PIN, bit);
	gpio_bit_write(MOTOR_W_ENABLE_PORT, MOTOR_W_ENABLE_PIN, bit);
}
